/*
 * timing-win32.c
 *
 *  Created on: 06.06.2012.
 *      Author: Aco
 */

#ifdef WIN32

#include "timing.h"

#include <windows.h>
#include <mmsystem.h>

// Kopirano i prilagodjeno za C iz clanka:
// http://msdn.microsoft.com/en-us/magazine/cc163996.aspx

typedef struct reference_point_S
{
  FILETIME file_time;
  LARGE_INTEGER counter;
} reference_point;

void simplistic_synchronize(reference_point * ref_point)
{
  FILETIME      ft0 = { 0, 0 },
                ft1 = { 0, 0 };
  LARGE_INTEGER li;

  //
  // Spin waiting for a change in system time. Get the matching
  // performance counter value for that time.
  //
  GetSystemTimeAsFileTime(&ft0);
  do
  {
    GetSystemTimeAsFileTime(&ft1);
    QueryPerformanceCounter(&li);
  }
  while ((ft0.dwHighDateTime == ft1.dwHighDateTime) &&
         (ft0.dwLowDateTime == ft1.dwLowDateTime));

  ref_point->file_time = ft1;
  ref_point->counter = li;
}

void get_time(LARGE_INTEGER frequency, const reference_point *
    reference, FILETIME * current_time)
{
  LARGE_INTEGER li;

  QueryPerformanceCounter(&li);

  //
  // Calculate performance counter ticks elapsed
  //
  LARGE_INTEGER ticks_elapsed;

  ticks_elapsed.QuadPart = li.QuadPart -
      reference->counter.QuadPart;

  //
  // Translate to 100-nanoseconds intervals (FILETIME
  // resolution) and add to
  // reference FILETIME to get current FILETIME.
  //
  ULARGE_INTEGER filetime_ticks,
                 filetime_ref_as_ul;

  filetime_ticks.QuadPart =
      (ULONGLONG)((((double)ticks_elapsed.QuadPart/(double)
      frequency.QuadPart)*10000000.0)+0.5);
  filetime_ref_as_ul.HighPart = reference->file_time.dwHighDateTime;
  filetime_ref_as_ul.LowPart = reference->file_time.dwLowDateTime;
  filetime_ref_as_ul.QuadPart += filetime_ticks.QuadPart;

  //
  // Copy to result
  //
  current_time->dwHighDateTime = filetime_ref_as_ul.HighPart;
  current_time->dwLowDateTime = filetime_ref_as_ul.LowPart;
}

int _timingInit = 0;
reference_point ref_point;
LARGE_INTEGER   frequency;

DWORD start;

void cu_initTiming()
{
	QueryPerformanceFrequency(&frequency);
	simplistic_synchronize(&ref_point);
	_timingInit = 1;

	start = GetTickCount();
}

CUSecTime cu_getSecTime()
{
	CUSecTime result;
	FILETIME        file_time;
	SYSTEMTIME      system_time;

	get_time(frequency, &ref_point, &file_time);
	FileTimeToSystemTime(&file_time, &system_time);

	result.seconds = system_time.wSecond;
	result.microSeconds = system_time.wMilliseconds * 1000;
	return result;
}

unsigned int cu_getTickCount()
{
	/*
	//CUSecTime result;
	FILETIME        file_time;
	//SYSTEMTIME      system_time;

	get_time(frequency, &ref_point, &file_time);
	//FileTimeToSystemTime(&file_time, &system_time);

	//result.seconds = system_time.wSecond;
	//result.microSeconds = system_time.wMilliseconds * 1000;
	return file_time.dwHighDateTime;
	*/
	return GetTickCount() - start;
}

#endif
